export class BlockGenerator {
    // 定义网格的类型，是一个二维数组，元素为数字类型
    constructor() {
        
    }
    
    /**
     * 判断在指定位置放置色块后是否会形成整行或整列都是同类型色块
     * @param x - 当前位置的行索引
     * @param y - 当前位置的列索引
     * @param type - 色块的类型
     * @param rows - 网格的行数
     * @param cols - 网格的列数
     * @param grid - 网格数组
     * @returns 如果会形成整行或整列返回 true，否则返回 false
     */
    private static willFormRowOrColumn(x: number, y: number, type: number, rows: number, cols: number, grid: number[][]): boolean {
        let isFullRow = true;
        for (let j = 0; j < cols; j++) {
            if (j !== y && grid[x][j] !== type) {
                isFullRow = false;
                break;
            }
        }
        if (isFullRow) return true;

        let isFullColumn = true;
        for (let i = 0; i < rows; i++) {
            if (i !== x && grid[i][y] !== type) {
                isFullColumn = false;
                break;
            }
        }
        return isFullColumn;
    }

    /**
     * 计算一个位置的启发式得分，用于选择更优的放置位置
     * @param x - 当前位置的行索引
     * @param y - 当前位置的列索引
     * @param rows - 网格的行数
     * @param cols - 网格的列数
     * @param grid - 网格数组
     * @param type - 色块的类型
     * @returns 该位置的启发式得分
     */
    private static heuristicScore(x: number, y: number, rows: number, cols: number, grid: number[][], type: number): number {
        const directions: [number, number][] = [[-1, 0], [1, 0], [0, -1], [0, 1]];
        let adjacentCount = 0;
        let emptyNeighbors = 0;

        for (const [dx, dy] of directions) {
            const newX = x + dx;
            const newY = y + dy;
            if (newX >= 0 && newX < rows && newY >= 0 && newY < cols) {
                if (grid[newX][newY] === type) {
                    adjacentCount++;
                } else if (grid[newX][newY] === 0) {
                    emptyNeighbors++;
                }
            }
        }

        // 优先选择相邻色块多且周围空白区域少的位置
        return adjacentCount * 10 - emptyNeighbors;
    }

    /**
     * 回溯函数，尝试递归地放置色块
     * @param x - 当前位置的行索引
     * @param y - 当前位置的列索引
     * @param type - 色块的类型
     * @param count - 需要放置的色块总数
     * @param placed - 已经放置的色块数量
     * @param rows - 网格的行数
     * @param cols - 网格的列数
     * @param grid - 网格数组
     * @returns 如果成功放置指定数量的色块返回 true，否则返回 false
     */
    private static backtrack(x: number, y: number, type: number, count: number, placed: number, rows: number, cols: number, grid: number[][]): boolean {
        if (placed === count) {
            return true;
        }

        const directions: [number, number][] = [[-1, 0], [1, 0], [0, -1], [0, 1]];
        const validNeighbors: [number, number][] = [];

        for (const [dx, dy] of directions) {
            const newX = x + dx;
            const newY = y + dy;
            if (
                newX >= 0 &&
                newX < rows &&
                newY >= 0 &&
                newY < cols &&
                grid[newX][newY] === 0 &&
                !this.willFormRowOrColumn(newX, newY, type, rows, cols, grid)
            ) {
                validNeighbors.push([newX, newY]);
            }
        }

        validNeighbors.sort((a, b) => {
            const scoreA = this.heuristicScore(a[0], a[1], rows, cols, grid, type);
            const scoreB = this.heuristicScore(b[0], b[1], rows, cols, grid, type);
            return scoreB - scoreA;
        });

        for (const [newX, newY] of validNeighbors) {
            grid[newX][newY] = type;
            if (this.backtrack(newX, newY, type, count, placed + 1, rows, cols, grid)) {
                return true;
            }
            grid[newX][newY] = 0; // 回溯
        }

        return false;
    }

    /**
     * 填充剩余数量的色块，确保达到指定的数量
     * @param type - 色块的类型
     * @param count - 需要放置的色块总数
     * @param rows - 网格的行数
     * @param cols - 网格的列数
     * @param grid - 网格数组
     */
    private static fillRemaining(type: number, count: number, rows: number, cols: number, grid:number[][]): void {
        // 计算还需要填充的色块数量
        let remaining = count - grid['flat']().filter(cell => cell === type).length;
        const emptyPositions: [number, number][] = [];
        for (let i = 0; i < rows; i++) {
            for (let j = 0; j < cols; j++) {
                if (grid[i][j] === 0 && !this.willFormRowOrColumn(i, j, type, rows, cols, grid)) {
                    emptyPositions.push([i, j]);
                }
            }
        }
        while (remaining > 0 && emptyPositions.length > 0) {
            const randomIndex = Math.floor(Math.random() * emptyPositions.length);
            const [x, y] = emptyPositions.splice(randomIndex, 1)[0];
            grid[x][y] = type;
            remaining--;
        }
    }

    /**
     * 生成指定类型和数量的连通色块
     * @param type - 色块的类型
     * @param count - 需要放置的色块总数
     * @param customGrid - 自定义的网格数组，如果不提供则使用默认网格
     * @returns 填充后的网格数组
     */
    public static generateConnectedBlocks(type: number, count: number, customGrid: number[][]): number[][] {
     
        const rows = customGrid.length;
        const cols = customGrid[0].length;

        let startX: number, startY: number;
        do {
            startX = Math.floor(Math.random() * rows);
            startY = Math.floor(Math.random() * cols);
        } while (customGrid[startX][startY] !== 0);

        customGrid[startX][startY] = type;
        this.backtrack(startX, startY, type, count, 1, rows, cols, customGrid);

        this.fillRemaining(type, count, rows, cols, customGrid);

        return customGrid;
    }
}
// interface gird